package com.hn.framework.aspectj.lang.log;

import com.hn.doc.xyj.annotation.Api;
import com.hn.framework.aspectj.lang.annotation.Log;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @author admin
 */
@Aspect
@Component
public class LogAop {

    private Logger loggerUser = LoggerFactory.getLogger("app-user");

    private static ThreadLocal<Map<String, Object>> threadLocal = new ThreadLocal<>();

    private static final String START_TIME = "startTime";

    private static final String REQUEST_PARAMS = "requestParams";

    @Pointcut("@annotation(com.hn.framework.aspectj.lang.annotation.Log) || " +
            "@annotation(com.hn.doc.xyj.annotation.Api)")
    public void annotationPointCut() {
    }

    @Before("annotationPointCut()")
    public void doBefore(JoinPoint joinPoint) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        // 开始时间。
        Map<String, Object> threadInfo = new HashMap<>();
        threadInfo.put(START_TIME, System.currentTimeMillis());
        // 请求参数。
        StringBuilder requestStr = new StringBuilder();
        Object[] args = joinPoint.getArgs();
        if (args != null && args.length > 0) {
            for (Object arg : args) {
                requestStr.append(String.valueOf(arg));
            }
        }
        threadInfo.put(REQUEST_PARAMS, requestStr.toString());
        threadLocal.set(threadInfo);

        loggerUser.info("请求url={},请求token={},请求id={},{}接口【{}】开始调用:requestData={}", request.getRequestURL().toString(),
                request.getHeader("token"), request.getAttribute("userId"), getTitle(joinPoint),
                joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName(),
                threadInfo.get(REQUEST_PARAMS));
    }

    @AfterReturning(value = "annotationPointCut()",returning = "res")
    public void doAfterReturning(JoinPoint joinPoint,Object res) {
        Map<String, Object> threadInfo = threadLocal.get();
        long takeTime = System.currentTimeMillis() - (long) threadInfo.getOrDefault(START_TIME, System.currentTimeMillis());
        threadLocal.remove();

        //logger.info("{}接口结束调用:耗时={}ms,result={}", log.title(), takeTime, res);
        loggerUser.info("{}接口结束调用:耗时={}ms,", getTitle(joinPoint), takeTime);
    }

    private String getTitle(JoinPoint joinPoint){
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Log log = method.getAnnotation(Log.class);
        if (log != null) {
            return log.title();
        } else {
            Api api = method.getAnnotation(Api.class);
            if (api != null) {
                return api.value();
            }
        }
        return "";
    }

}
